package service

import (
	"errors"
	"fmt"
	"gitee.com/sansaniot/ssiot-core/httpmvc/service"
	"github.com/gin-gonic/gin"
	uuid "github.com/satori/go.uuid"
	"github.com/xuri/excelize/v2"
	"gorm.io/gorm"
	"net/url"
	cDto "ssadmin/common/query"
	"ssadmin/common/utils"
	"ssadmin/internal/admin/models"
	"ssadmin/internal/admin/models/command"
	dto "ssadmin/internal/admin/models/query"
	"strconv"
	"strings"
	"time"
)

type SysDictType struct {
	service.Service
}

// GetPage 获取列表
func (e *SysDictType) GetPage(c *dto.SysDictTypeGetPageReq, list *[]models.SysDictType, count *int64) error {
	var err error
	var data models.SysDictType

	err = e.Orm.Model(&data).
		Scopes(
			cDto.MakeCondition(c.GetNeedSearch()),
			cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
		).
		Find(list).Limit(-1).Offset(-1).
		Count(count).Error
	if err != nil {
		e.Log.Errorf("db error: %s", err)
		return err
	}
	return nil
}

// Get 获取对象
func (e *SysDictType) Get(d *dto.SysDictTypeGetReq, model *models.SysDictType) error {
	var err error

	db := e.Orm.First(model, d.GetId())
	err = db.Error
	if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
		err = errors.New("查看对象不存在或无权查看")
		e.Log.Errorf("db error: %s", err)
		return err
	}
	if db.Error != nil {
		e.Log.Errorf("db error: %s", err)
		return err
	}
	return nil
}

// Insert 创建对象
func (e *SysDictType) Insert(c *command.SysDictTypeInsertReq) error {
	var err error
	var data models.SysDictType
	c.Generate(&data)
	var count int64
	e.Orm.Model(&data).Where("dict_type = ? and system_id = ? ", data.DictType, data.SystemId).Count(&count)
	if count > 0 {
		return errors.New(fmt.Sprintf("当前系统[%s]的字典类型[%s]已经存在！", data.SystemId, data.DictType))
	}
	err = e.Orm.Create(&data).Error
	if err != nil {
		e.Log.Errorf("db error: %s", err)
		return err
	}
	return nil
}

// Update 修改对象
func (e *SysDictType) Update(c *command.SysDictTypeUpdateReq) error {
	var err error
	var model = models.SysDictType{}
	e.Orm.First(&model, c.GetId())
	c.Generate(&model)
	db := e.Orm.Save(&model)
	if db.Error != nil {
		e.Log.Errorf("db error: %s", err)
		return err
	}
	if db.RowsAffected == 0 {
		return errors.New("无权更新该数据")

	}
	return nil
}

// Remove 删除
func (e *SysDictType) Remove(d *command.SysDictTypeDeleteReq) error {
	var err error
	var data models.SysDictType
	//删除字典数据
	list := make([]models.SysDictType, 0)
	err = e.Orm.Model(&data).
		Scopes(
			cDto.MakeCondition(dto.SysDictTypeGetPageReq{DictId: d.Ids}),
		).
		Find(&list).Limit(-1).Offset(-1).Error
	if err != nil {
		err = errors.New("查询字典出错")
		return err
	}
	var dictData models.SysDictData
	for _, v := range list {
		systemId := v.SystemId
		if len(systemId) == 0 {
			continue
		}
		db := e.Orm.Where("dict_type = ? and system_id = ?", v.DictType, systemId).Delete(&dictData)
		if db.Error != nil {
			err = db.Error
			e.Log.Errorf("Delete error: %s", err)
			continue
		}
	}
	//删除字典类型
	db := e.Orm.Delete(&data, d.GetId())
	if db.Error != nil {
		err = db.Error
		e.Log.Errorf("Delete error: %s", err)
		return err
	}
	if db.RowsAffected == 0 {
		err = errors.New("无权删除该数据")
		return err
	}
	return nil
}

// GetAll 获取所有
func (e *SysDictType) GetAll(c *dto.SysDictTypeGetPageReq, list *[]models.SysDictType) error {
	var err error
	var data models.SysDictType

	err = e.Orm.Model(&data).
		Scopes(
			cDto.MakeCondition(c.GetNeedSearch()),
		).
		Find(list).Error
	if err != nil {
		e.Log.Errorf("db error: %s", err)
		return err
	}
	return nil
}

// 导出
func (d *SysDictType) ExportDictType(c *gin.Context, m *models.SysDictType, req *dto.SysDictTypeGetPageReq) error {
	req.PageIndex = 0
	list := make([]models.SysDictType, 0)
	err := d.Orm.Model(m).
		Scopes(
			cDto.MakeCondition(req.GetNeedSearch()),
		).
		Find(&list).Limit(-1).Offset(-1).Error
	if err != nil {
		return err
	}
	if len(list) == 0 {
		return errors.New("查无数据")
	}
	// 生成模板
	f := excelize.NewFile()
	defer f.Close()
	// 模板内容
	if err := FillExportDictType(f, list); err != nil {
		return err
	}
	// 删除excelize的默认sheet
	f.DeleteSheet("Sheet1")
	// 响应文件流
	fileName := fmt.Sprintf("字典类型.xlsx")
	c.Header("Content-Disposition", fmt.Sprintf("attachment; filename*=utf-8''%s", url.QueryEscape(fileName)))
	c.Header("File-Name", url.QueryEscape(fileName))
	c.Header("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8")
	if _, err := f.WriteTo(c.Writer); err != nil {
		_, _ = fmt.Fprintf(c.Writer, err.Error())
		return err
	}
	return nil
}

func (d *SysDictType) ImportDictType(c *gin.Context, m *models.SysDictType, req *dto.SysDictTypeGetPageReq) error {
	// 获取文件对象
	file, header, err := c.Request.FormFile("file")
	if err != nil {
		return err
	}
	if file == nil || !strings.HasSuffix(header.Filename, ".xlsx") {
		return errors.New("非法文件，请使用正确的文件导入")
	}
	defer file.Close()
	f, err := excelize.OpenReader(file)
	if err != nil {
		return err
	}
	// 执行导入
	if err = ImportDictType(m, f, req); err != nil {
		return err
	}
	return nil
}

/**
DictName string `json:"dictName" gorm:"size:128;comment:DictName"`
DictType string `json:"dictType" gorm:"size:128;comment:DictType"`
Status   int    `json:"status" gorm:"size:4;comment:Status"`
Remark   string `json:"remark" gorm:"size:255;comment:Remark"`
SystemId string `json:"systemId" gorm:"size:255;comment:SystemId"`
BizId    string `json:"bizId" gorm:"size:255;comment:BizId"`
*/
var (
	DictTypeHeaderName = []string{"字典名称", "字典类型", "备注", "业务ID"}
	DictTypeHeaderKey  = []string{"dictName", "dictType", "remark", "bizId"}
)

// 导出内容填充
func FillExportDictType(f *excelize.File, dictTypes []models.SysDictType) error {
	// 头部单元格样式
	headerCellStyle, _ := f.NewStyle(&excelize.Style{
		Font: &excelize.Font{
			Bold: true,
		},
		Alignment: &excelize.Alignment{
			Horizontal: "center",
			Vertical:   "center",
		},
		Border: []excelize.Border{
			{Type: "left", Color: "000000", Style: 1},
			{Type: "top", Color: "000000", Style: 1},
			{Type: "bottom", Color: "000000", Style: 1},
			{Type: "right", Color: "000000", Style: 1},
		},
	})
	sheetName := "字典类型"
	_, _ = f.NewSheet(sheetName)
	// 第1行
	_ = f.InsertRows(sheetName, 1, 1)
	colNum := len(DictTypeHeaderName)
	for n := 0; n < colNum; n++ {
		axis, _ := excelize.ColumnNumberToName(n + 1)
		_ = f.SetCellValue(sheetName, axis+"1", DictTypeHeaderName[n])
		_ = f.SetCellStyle(sheetName, axis+"1", axis+"1", headerCellStyle)
		_ = f.SetColWidth(sheetName, axis, axis, 20)
	}
	// 数据行起始
	startRow := 2
	size := len(DictTypeHeaderKey)
	// 填充已有数据模型
	dictTypesSize := len(dictTypes)
	for row := startRow; row-startRow < dictTypesSize; row++ {
		_ = f.InsertRows(sheetName, row, 1)
		dictType := dictTypes[row-startRow]
		rowStr := strconv.Itoa(row)
		for colIndex := 0; colIndex < size; colIndex++ {
			key := DictTypeHeaderKey[colIndex]
			axis, _ := excelize.ColumnNumberToName(colIndex + 1)
			//"dictName", "dictType", "remark","bizId"
			switch key {
			case "dictName":
				_ = f.SetCellValue(sheetName, axis+rowStr, dictType.DictName)
				break
			case "dictType":
				_ = f.SetCellValue(sheetName, axis+rowStr, dictType.DictType)
				break
			case "remark":
				_ = f.SetCellValue(sheetName, axis+rowStr, dictType.Remark)
				break
			case "bizId":
				_ = f.SetColWidth(sheetName, axis, axis, 10)
				_ = f.SetCellValue(sheetName, axis+rowStr, dictType.BizId)
				break
			default:
				break
			}
		}
	}
	return nil
}

func ImportDictType(dictTypeModel *models.SysDictType, f *excelize.File, req *dto.SysDictTypeGetPageReq) error {
	sheetNum := f.SheetCount
	if sheetNum == 0 {
		return nil
	}
	// 解析
	dictTypes := make([]models.SysDictType, 0)
	errorInfo := ""
	for _, sheetName := range f.GetSheetList() {
		// 遍历
		rowIndexRead := make([]int, 0)
		//sheetErrPre := fmt.Sprintf("<br>(sheet: %s)<br>", sheetName)
		headerNames := DictTypeHeaderName
		headerKeys := DictTypeHeaderKey
		// 按行获取[][]单元格值，f.Rows迭代器不能过滤掉空内容的行
		rows, err := f.GetRows(sheetName)
		if err != nil {
			fmt.Println(err)
		}
		cols, err := f.GetCols(sheetName)
		if err != nil {
			fmt.Println(err)
		}
		maxRowNumber := len(rows)
		maxColNumber := len(cols)
		if maxRowNumber <= 1 {
			errorInfo += fmt.Sprintf("模板内容为空(sheet:%s)", sheetName)
			continue
		}
		if maxColNumber != len(headerNames) {
			return errors.New("无效的导入文件，请重新导出文件填写内容")
		}
		for rowIndex, rowColumns := range rows {
			if utils.GetCommUtil().IntIn(rowIndex, rowIndexRead) {
				// 效率优化 (每sheet中 遍历过的行跳过)
				continue
			}
			if rowIndex == 0 {
				rowIndexRead = append(rowIndexRead, rowIndex)
				continue
			}
			// 第2行起 为数据内容 解析行数据
			rowIndexRead = append(rowIndexRead, rowIndex)
			dictType := models.SysDictType{}
			for colNum, rowValue := range rowColumns {
				key := headerKeys[colNum]
				switch key {
				case "dictName":
					dictType.DictName = rowValue
					break
				case "dictType":
					dictType.DictType = rowValue
					break
				case "remark":
					dictType.Remark = rowValue
					break
				case "bizId":
					dictType.BizId = rowValue
					break
				default:
					break
				}

			}
			dictTypes = append(dictTypes, dictType)
		}
		if len(errorInfo) > 0 {
			return errors.New(errorInfo)
		}
		for i, v := range dictTypes {
			//查找是否存在
			fmt.Println(v)
			fmt.Println(req)
			req.DictType = v.DictType
			list := make([]models.SysDictType, 0)
			err = dictTypeModel.Orm.Model(dictTypeModel).
				Scopes(
					cDto.MakeCondition(req.GetNeedSearch()),
				).
				Find(&list).Limit(-1).Offset(-1).Error
			if err != nil {
				errorInfo += fmt.Sprintf("查询字典类型异常(rowIndex:%d)", i)
				return errors.New(errorInfo)
			}
			//存在则更新
			if len(list) > 0 {
				oldModel := list[0]
				oldModel.DictType = v.DictType
				oldModel.DictName = v.DictName
				oldModel.Remark = v.Remark
				oldModel.BizId = v.BizId
				oldModel.UpdatedAt = time.Now()
				err = dictTypeModel.Orm.Model(&dictTypeModel).Where("dict_id = ?", oldModel.ID).Updates(&oldModel).Error
				if err != nil {
					errorInfo += fmt.Sprintf("更新字典类型异常(rowIndex:%d)", i)
					return errors.New(errorInfo)
				}
			} else {
				//不存在则插入
				oldModel := models.SysDictType{}
				oldModel.DictType = v.DictType
				oldModel.DictName = v.DictName
				oldModel.Remark = v.Remark
				oldModel.BizId = v.BizId
				oldModel.Status = 1
				oldModel.SystemId = req.SystemId
				oldModel.ID = uuid.NewV4().String()
				oldModel.CreatedAt = time.Now()
				oldModel.UpdatedAt = time.Now()
				err = dictTypeModel.Orm.Model(&dictTypeModel).Create(&oldModel).Error
				if err != nil {
					errorInfo += fmt.Sprintf("新增字典类型异常(rowIndex:%d)", i)
					return errors.New(errorInfo)
				}
			}

		}
	}
	return nil
}
